﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Printing;
using UnityScriptEngine;

namespace MBBStoreClient
{
    public partial class frmInventoryImport : Form
    {
        UnityProcessor proc = new UnityProcessor();
        UnityScript itemBuf = new UnityScript("IMPORTDATA", 3);
        UnityScript itemUpdate = new UnityScript("UPDATEDATA", 3);
        UnityScript itemAdd = new UnityScript("ADDDATA", new object[] { "fBarcode", "fDescription", "fQty" });
        UnityScript itemComputed = new UnityScript("COMPUTED", new object[] {"fBarcode", "fDescription", "fQty", "fPrice", "fAmt"});

        float grandTotal = 0f;
        Threader t = new Threader();
        ImportType it = new ImportType();
        public frmInventoryImport()
        {
            InitializeComponent();
            InitializeFrameSliderForm();
        }
        private void InitializeForm()
        {
            
            proc.ProcessCompleted += new ProcessHandler(proc_ProcessCompleted);
            proc.ProcessError += new ProcessHandler(proc_ProcessError);
            btnLoad.Click += new EventHandler(btnLoad_Click);
            btnImport.Click += new EventHandler(btnImport_Click);
            btnPrint.Click += new EventHandler(btnPrint_Click);
            chkReset.CheckedChanged += new EventHandler(chkReset_CheckedChanged);
            chkMoneyValue.CheckedChanged += new EventHandler(chkMoneyValue_CheckedChanged);
            it.ProcessCompleted += new UnityCore.CoreHandler(it_ProcessCompleted);
            it.ProcessProgress += new UnityCore.CoreHandler(it_ProcessProgress);
            it.ProcessError += new UnityCore.CoreHandler(it_ProcessError);

            lblInst.Text = "Note:" +
                "- To import whole stock to database please UNCHECK the Compute for Money Value option. Check this option if the data being" +
                "imported is to be saved to a file as computed money value only.";
        }

        void btnPrint_Click(object sender, EventArgs e)
        {
            if (grd.Rows.Count > 0)
            {
                frmInventoryEncoderName frmEncName = new frmInventoryEncoderName();
                DialogResult dlg = frmEncName.ShowDialog();
                if (dlg == System.Windows.Forms.DialogResult.Cancel) return;
                encName = frmEncName.EncoderName;
                officerName = frmEncName.OfficerName;

                PrintDocument pd = new PrintDocument();
                pd.DocumentName = lblText.Text;
                pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
                PrintDialog pdlg = new PrintDialog();
                pdlg.Document = pd;
                if (pdlg.ShowDialog() == DialogResult.OK)
                {
                    pageNum = 1;
                    PrintPreviewDialog ppdlg = new PrintPreviewDialog();
                    ppdlg.Document = pd;
                    ppdlg.ShowDialog();
                }
            }
            else
            {
                MessageBox.Show("WARNING! You can only print if data is available.", "Print Data", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
        int sumRow = 0, pageNum=1;
        string encName = "", officerName = "";
        void pd_PrintPage(object sender, PrintPageEventArgs e)
        {
            float tm = 50f;
            float lm = 50f;
            float rm = e.PageBounds.Width - 50;
            float bm = e.PageBounds.Height - 50;
            
            float y = tm;
            Font f = new Font("Courier New", 10f);
            StringFormat sf = new StringFormat();
            
            sf.Alignment = StringAlignment.Center;
            e.Graphics.DrawString("MONETARY VALUE SUMMARY of "+ StoreClientModule.Common.lStoreName, f, Brushes.Black, e.PageBounds.Width / 2, y,sf);

            sf.Alignment = StringAlignment.Far;
            e.Graphics.DrawString("Page : "+ pageNum, f, Brushes.Black, e.PageBounds.Width - 100, y, sf);

            y += CrLf(f, e);
            sf.Alignment = StringAlignment.Center;
            e.Graphics.DrawString("Encoder:" + encName + ", Inventory Officer:" + officerName, f, Brushes.Black, e.PageBounds.Width / 2, y, sf);

            y += CrLf(f, e) * 2;

            sf.Alignment = StringAlignment.Center;
            f = new Font("Courier New", 10f, FontStyle.Bold);
            float[] colPos = new float[] { 100f, 300f, 550f, 650f, 750f };
            for (int i = 0; i < grd.Columns.Count; i++)
            {
                e.Graphics.DrawString(grd.Columns[i].HeaderText, f, Brushes.Black, colPos[i], y,sf);
            }
            y += CrLf(f, e);

            sf.Alignment = StringAlignment.Near;
            f = new Font("Courier New", 10f);
            int adj = -50;
            //for (int r = 0; r < grd.Rows.Count; r++)
            float subtotal= 0f;
            while (y < bm && sumRow < grd.Rows.Count)
            {
                for (int c = 0; c < grd.Columns.Count; c++)
                {
                    string toPrint= grd.Rows[sumRow].Cells[c].Value.ToString();
                    if (c == 1 && toPrint.Length > 30) toPrint = toPrint.Substring(0, 30) + "...";
                    if (c < 2)
                    {
                        sf.Alignment = StringAlignment.Near;
                        adj = -50;
                    }
                    else
                    {
                        sf.Alignment = StringAlignment.Far;
                        adj = 50;
                        toPrint = float.Parse(toPrint).ToString("#,#0.00");
                    }
                    e.Graphics.DrawString(toPrint, f, Brushes.Black, colPos[c]+adj, y,sf);
                    if(c == 4) subtotal += float.Parse( grd.Rows[sumRow].Cells[c].Value.ToString());
                }
                y += CrLf(f, e);
                sumRow++;
            }
            sf.Alignment = StringAlignment.Near;
            e.Graphics.DrawString("SubTotal", f, Brushes.Black, colPos[3] - 50, y, sf);
            sf.Alignment = StringAlignment.Far;
            e.Graphics.DrawString(subtotal.ToString("#,#0.00"), f, Brushes.Black, colPos[4] + 50, y, sf);
            if (sumRow < grd.Rows.Count - 1)
            {
                e.HasMorePages = true;
                pageNum++;
            }
            else
            {
                y += CrLf(f, e) * 2;
                sf.Alignment = StringAlignment.Near;
                e.Graphics.DrawString("GrandTotal", f, Brushes.Black, colPos[3] - 50, y, sf);
                sf.Alignment = StringAlignment.Far;
                e.Graphics.DrawString(txtTotal.Text, f, Brushes.Black, colPos[4] + 50, y, sf);
                e.HasMorePages = false;
                sumRow = 0;
                pageNum = 1;
            }
        }
        float CrLf(Font f, PrintPageEventArgs e)
        {
            float tmp = f.GetHeight(e.Graphics);
            return tmp;
        }
        void chkMoneyValue_CheckedChanged(object sender, EventArgs e)
        {
            if (chkMoneyValue.Checked)
            {
                grpSummary.Visible = true;
            }
            else
            {
                grpSummary.Visible = false;
            }
        }

        void it_ProcessError(string pcode, string msg)
        {
            t.SafeCall(this, delegate
            {
                MessageBox.Show(msg, pcode, MessageBoxButtons.OK, MessageBoxIcon.Error);
            });
        }
        void chkReset_CheckedChanged(object sender, EventArgs e)
        {
            if (chkReset.Checked)
            {
                MessageBox.Show("WARNING! Checking this box will reset all inventory values to zero.\r\n" +
                    "Uncheck this option to add the values during import instead.", "Import Inventory Data", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        void it_ProcessProgress(string pcode, string msg)
        {
            t.SafeCall(this, delegate
            {
                prgBar.Value = (int)float.Parse(msg.ToString());
                lblProg.Text = (prgBar.Value / 2) + "%";
                    
            });
        }

        void it_ProcessCompleted(string pcode, string msg)
        {
            t.SafeCall(this, delegate
            {

                if (pcode == "DOIMPORT")
                {
                    if (itemUpdate.Data_Count > 0)
                    {
                        itemUpdate.Script_Clear();
                        itemUpdate.Script_Add(Script.PROC_NAME, "UPDATESTOCK");
                        itemUpdate.Script_Add(Script.DBPU_UPDATE);
                    }
                    if (itemAdd.Data_Count > 0)
                    {
                        itemAdd.Script_Clear();
                        itemAdd.Script_Add(Script.PROC_NAME, "ADDSTOCK");
                        itemAdd.Script_Add(Script.DBPU_ADD, "SELECT * FROM tblproductstockwhole", false);
                    }
                    if (itemUpdate.Data_Count > 0)
                        proc.Run(itemUpdate);
                    else
                        proc.Run(itemAdd);
                }
                else if (pcode == "DOCOMPUTE")
                {
                    prgBar.Value = 200;
                    lblProg.Text = "100%";
                    float total = 0f;
                    for (int i = 0; i < itemComputed.Data_Count; i++)
                    {
                        UnityElement icmp;
                        itemComputed.Data_Get(i, out icmp);
                        total += float.Parse(icmp.Data_GetField(4).ToString());
                    }
                    grandTotal = total;
                    txtTotal.Text = grandTotal.ToString("#,#0.00");
                    lblItems.Text = itemComputed.Data_Count.ToString() + " Item(s)";
                    grd.DataSource = itemComputed.ToDataTable();
                    grd.Columns[3].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
                    grd.Columns[4].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
                    chkMoneyValue.Enabled = false;
                    chkReset.Enabled = false;
                    States(true);
                }
 
            });
        }

        void btnImport_Click(object sender, EventArgs e)
        {
            if (chkMoneyValue.Checked)
            {
                MessageBox.Show("WARNING! The money value computation will now commence.\r\n" +
                    "Please DO NOT close the window or the application.", "Import Inventory Data", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                MessageBox.Show("WARNING! The inventory data import process will now commence.\r\n" +
                        "Please DO NOT close the window or the application.", "Import Inventory Data", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            prgBar.Value = 0;
            lblProg.Text = "0%";
            States(false);
            itemUpdate.Script_Clear();
            itemUpdate.Script_Add(Script.PROC_NAME, "GETSTOCK");
            if (chkMoneyValue.Checked)
            {
                itemAdd = new UnityScript("ADDDATA", new object[] { "fBarcode", "fDescription", "fQty", "fPrice", "fAmt" });
                itemUpdate.Script_Add(Script.DBPU_FETCH, "SELECT * FROM tblproducts");
            }
            else
            {
                itemAdd = new UnityScript("ADDDATA", new object[] { "fBarcode", "fDescription", "fQty" });
                itemUpdate.Script_Add(Script.DBPU_FETCH, "SELECT * FROM tblproductstockwhole");
            }
            proc.Run(itemUpdate);
        }

        void btnLoad_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "Open Saved Inventory Data";
            dlg.Filter = "All|*.*|Save Inventory Data|*.sid";
            dlg.FilterIndex = 2;
            dlg.AddExtension = true;
            dlg.CheckPathExists = true;
            dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                States(false);
                itemBuf.Script_Clear();
                itemBuf.Script_Add(Script.PROC_NAME, "READBUFFER");
                itemBuf.Script_Add(Script.LFFPU_READ, dlg.FileName, "elayorbulc");
                proc.Run(itemBuf);
                chkReset.Checked = false;
            } 
        }

        void proc_ProcessError(string id, string desc)
        {
            t.SafeCall(this, delegate
            {
                MessageBox.Show(desc, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
            });
        }

        void proc_ProcessCompleted(string id, string desc)
        {
            t.SafeCall(this, delegate
            {
                switch (id)
                {
                    case "READBUFFER":
                        proc.Data_Fetch(out itemBuf);
                        txtTitle.Text = itemBuf.Desc_FileTitle;
                        txtDescription.Text = itemBuf.Desc_MetaData;
                        txtCount.Text = itemBuf.Data_Count.ToString();
                        States(true);
                        break;
                    case "GETSTOCK":
                        proc.Data_Fetch(out itemUpdate);
                        if (chkMoneyValue.Checked)
                        {
                            it.DoCompute(itemBuf, itemUpdate, ref itemComputed);
                        }
                        else
                        {
                            it.DoImport(ref itemBuf, ref itemUpdate, ref itemAdd, chkReset.Checked);
                        }
                        break;
                    case "ADDSTOCK":
                        States(true);
                        chkReset.Checked = false;
                        chkMoneyValue.Enabled = false;
                        prgBar.Value = 200;
                        lblProg.Text = (prgBar.Value / 2) + "%";
                        System.Threading.Thread.Sleep(1000);

                        break;
                    case "UPDATESTOCK":
                        if (itemAdd.Data_Count > 0)
                        {
                            prgBar.Value = 150;
                            lblProg.Text = (prgBar.Value / 2) + "%";
                            proc.Run(itemAdd);
                        }
                        else
                        {
                            States(true);
                            chkReset.Checked = false;
                            chkMoneyValue.Enabled = false;
                            prgBar.Value = 200;
                            lblProg.Text = (prgBar.Value / 2) + "%";
                            System.Threading.Thread.Sleep(1000);
                        }
                        break;
                }
            });
        }
        void States(bool state)
        {
            grpData.Enabled = state;
            grpProgress.Enabled = state;
            grpFun.Enabled = state;
            grpSummary.Enabled = state;
        }
        
    }
    class ImportType : UnityCore.UnityProcessCall
    {
        UnityScript[] usbuf = new UnityScript[3];
        bool _replace = false;
        float prog = 0f;
        void _DoImport(object p, out object e)
        {
           
            UnityCore.UnityProcess proc = new UnityCore.UnityProcess() { ID = "DOIMPORT", HasError = false };
            try
            {
                UnityScript itemBuf, itemStock, itemAdd;
                itemBuf = usbuf[0];
                itemStock = usbuf[1];
                itemAdd = usbuf[2];
                prog = 0f;
                //Reset values
                /*if (_replace)
                {
                    for (int stkCnt = 0; stkCnt < itemStock.Data_Count; stkCnt++)
                    {
                        UnityElement stk;
                        itemStock.Data_Get(stkCnt, out stk);
                        stk.Data_SetField(2, "0");
                    }
                }*/
                //Importing process.
                for (int bufCnt = 0; bufCnt < itemBuf.Data_Count; bufCnt++)
                {
                    prog++;
                    SetProcessProgress(proc, (prog/itemBuf.Data_Count) * 100);
                    bool found = false;
                    UnityElement buf;
                    itemBuf.Data_Get(bufCnt, out buf);
                    for (int stkCnt = 0; stkCnt < itemStock.Data_Count; stkCnt++)
                    {
                        UnityElement stk;
                        itemStock.Data_Get(stkCnt, out stk);
                        float curVal = 0f;
                        if (buf.Data_GetField(0).ToString().Equals(stk.Data_GetField(0).ToString()))
                        {
                            if (_replace)
                            {
                                //stk.Data_SetField(2, buf.Data_GetField(2));
                                //stk.Flag_ForceOverWrite();
                                curVal = float.Parse(buf.Data_GetField(2).ToString());
                            }
                            else
                            {
                                curVal = float.Parse(stk.Data_GetField(2).ToString()) + float.Parse(buf.Data_GetField(2).ToString());
                            }
                            stk.Data_SetField(2, curVal);
                            stk.Flag_ForceOverWrite();
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        bool isAdded = false;
                        UnityElement newBuf;
                        for (int newCnt = 0; newCnt < itemAdd.Data_Count; newCnt++)
                        {
                            itemAdd.Data_Get(newCnt, out newBuf);
                            if (newBuf.Data_GetField(0).ToString().Equals(buf.Data_GetField(0).ToString()))
                            {
                                isAdded = true;
                                float curQty = float.Parse(buf.Data_GetField(2).ToString()) + float.Parse(newBuf.Data_GetField(2).ToString());
                                newBuf.Data_SetField(2, curQty);
                                break;
                            }
                        }
                        if (!isAdded)
                        {
                            newBuf = new UnityElement(itemAdd.Desc_Fields());
                            newBuf.Data_SetField(0, buf.Data_GetField(0));
                            newBuf.Data_SetField(1, buf.Data_GetField(1));
                            newBuf.Data_SetField(2, buf.Data_GetField(2));
                            itemAdd.Data_AddNew(newBuf);
                        }
                    }
                    System.Threading.Thread.Sleep(1);
                }
            }
            catch (Exception ex)
            {
                proc.Msg = ex.Message;
                proc.HasError = true;
            }
            finally
            {
                e = proc;
            }
        }
        void _DoCompute(object p, out object e)
        {
            UnityCore.UnityProcess proc = new UnityCore.UnityProcess() { ID = "DOCOMPUTE", HasError = false };
            try
            {
                UnityScript itemBuf, itemProd, itemAdd, itemComp;
                itemBuf = usbuf[0];
                itemProd = usbuf[1];
                itemComp = usbuf[2];
                itemAdd = new UnityScript("ADDDATA", new object[] { "fBarcode", "fDescription", "fQty", "fPrice", "fAmt" });
                prog = 0f;
                for (int bufCnt = 0; bufCnt < itemBuf.Data_Count; bufCnt++)
                {
                    UnityElement ibuf;
                    itemBuf.Data_Get(bufCnt, out ibuf);
                    UnityElement iadd = new UnityElement(itemComp.Desc_Fields());
                    iadd.Data_SetField(0, ibuf.Data_GetField(0));
                    iadd.Data_SetField(1, ibuf.Data_GetField(1));
                    iadd.Data_SetField(2, ibuf.Data_GetField(2));
                    prog++;
                    SetProcessProgress(proc, (prog / itemBuf.Data_Count) * 200);
                    bool regfound = false;
                    for (int prdCnt = 0; prdCnt < itemProd.Data_Count; prdCnt++)
                    {
                        UnityElement iprd;
                        itemProd.Data_Get(prdCnt, out iprd);
                        
                        if (iadd.Data_GetField(0).ToString().Equals(iprd.Data_GetField(0).ToString()))
                        {
                            float price = 0f;
                            regfound = true;
                            try
                            {
                                price = float.Parse(iprd.Data_GetField(2).ToString());
                            }
                            catch (Exception ex) 
                            { 
                                //MessageBox.Show(iadd.Data_GetField(2).ToString()+","+iprd.Data_GetField(2).ToString()+","+iprd.Data_GetField(2).ToString();
                            };
                            iadd.Data_SetField(3, price.ToString("#,#0.00"));
                            bool addFound = false;
                            for (int addCnt = 0; addCnt < itemComp.Data_Count; addCnt++)
                            {
                                UnityElement icur;
                                itemComp.Data_Get(addCnt, out icur);
                                if (iadd.Data_GetField(0).ToString().Equals(icur.Data_GetField(0).ToString()))
                                {
                                    float qty = float.Parse(iadd.Data_GetField(2).ToString()) + float.Parse(icur.Data_GetField(2).ToString());
                                    icur.Data_SetField(2, qty);
                                    addFound = true;
                                    break;
                                }
                            }
                            if (!addFound) itemComp.Data_AddNew(iadd);
                            break;
                        }
                    }
                    if (!regfound) MessageBox.Show("The item " + iadd.Data_GetField(0).ToString() + " cannot be found in products table, please update first to get accurate results!", "Compute", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    for (int i = 0; i < itemComp.Data_Count; i++)
                    {
                        UnityElement icur;
                        itemComp.Data_Get(i, out icur);
                        float qty = float.Parse(icur.Data_GetField(2).ToString());
                        float price = float.Parse(icur.Data_GetField(3).ToString());
                        icur.Data_SetField(4, Math.Round((qty * price),2).ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                proc.Msg = ex.Message;
                proc.HasError = true;
            }
            finally
            {
                e = proc;
            }
        }
        public void DoImport(ref UnityScript itemBuf, ref UnityScript itemStock, ref UnityScript itemAdd, bool replace)
        {
            UnityCore.ThreadHandler id = new UnityCore.ThreadHandler(_DoImport);
            AsyncCallback ac = new AsyncCallback(GenericCB);
            usbuf[0] = itemBuf;
            usbuf[1] = itemStock;
            usbuf[2] = itemAdd;
            _replace= replace;
            object e;
            IAsyncResult ar = id.BeginInvoke(usbuf,out e, ac, null);
        }
        public void DoCompute(UnityScript itemBuf, UnityScript itemProd, ref UnityScript itemCmp)
        {
            UnityCore.ThreadHandler id = new UnityCore.ThreadHandler(_DoCompute);
            AsyncCallback ac = new AsyncCallback(GenericCB);
            usbuf[0] = itemBuf;
            usbuf[1] = itemProd;
            usbuf[2] = itemCmp;
            object e;
            IAsyncResult ar = id.BeginInvoke(usbuf, out e, ac, null);
        }

    }
}
